﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace RecipeRecommender
{
    class RecipeUtil
    {

        public static List<Recipe> RecipeList = new List<Recipe>();
        public static string[] recipeFileList = Directory.GetFiles(@"CBRData/Recipe/", "*.txt");
        private const string WEIGHT_CONFIG_FILE_NAME = "CBRData\\WeightConfig.txt";

        public static Dictionary<string, int> weightConfigMap = new Dictionary<string, int>();
        public static void setAllRecipes()
        {

            foreach (string fileName in recipeFileList)
            {
                if (!File.Exists(fileName))
                {
                    Console.WriteLine("{0} does not exist.", fileName);
                    continue;
                }

                using (StreamReader sr = File.OpenText(fileName))
                {
                    String name = sr.ReadLine().Trim();

                    String cuisineString = sr.ReadLine().Trim();
                    Cuisine cuisine = CuisineUtil.getCuisineByName(cuisineString);
                    if (cuisine == null) throw new Exception("Cuisine is null");

                    String mealTypeString = sr.ReadLine().Trim();
                    MealType mealType = MealTypeUtil.getMealTypeByName(mealTypeString);
                    if (mealType == null) throw new Exception("Meal Type is null");

                    String cookingMethodString = sr.ReadLine().Trim();
                    CookingMethod cookingMethod = CookingMethodUtil.getCookingMethodByName(cookingMethodString);
                    if (cookingMethod == null) throw new Exception("Cooking Method Type is null");

                    String spicyString = sr.ReadLine().Trim();
                    bool? spicy = !spicyString.ToUpper().Contains("NON");

                    String halalString = sr.ReadLine().Trim();
                    bool? halal = !halalString.ToUpper().Contains("NON");

                    String healthyString = sr.ReadLine().Trim();
                    bool? healthy = !healthyString.ToUpper().Contains("NON");

                    String vegetarianString = sr.ReadLine().Trim();
                    bool? vegetarian = !vegetarianString.ToUpper().Contains("NON");

                    int? cookingTime = Convert.ToInt32(sr.ReadLine().Trim());
                    int? servingPortion = Convert.ToInt32(sr.ReadLine().Trim());

                    sr.ReadLine();
                    sr.ReadLine();
                    List<Ingredient> IngredientList = new List<Ingredient>();
                    String ingredientName;
                    while (!(ingredientName = sr.ReadLine().Trim()).Equals(String.Empty))
                    {
                        Ingredient ingredient = IngredientUtil.getIngredientByName(ingredientName);
                        if (ingredient != null)
                            IngredientList.Add(ingredient);
                    }
                    sr.ReadLine();

                    StringBuilder instructions = new StringBuilder();
                    String instruction;
                    while ((instruction = sr.ReadLine()) != null)
                    {
                        instructions.AppendLine(instruction);
                    }

                    Console.WriteLine("The end of the stream has been reached.");

                    Recipe recipe = new Recipe();
                    recipe.CookingInstructions = instructions.ToString();
                    recipe.CookingMethod = cookingMethod;
                    recipe.CookingTime = cookingTime;
                    recipe.Cuisine = cuisine;
                    recipe.Halal = halal;
                    recipe.Healthy = healthy;
                    recipe.Ingredients = IngredientList;
                    recipe.MealType = mealType;
                    recipe.Name = name;
                    recipe.ServingPortion = servingPortion;
                    recipe.Spicy = spicy;
                    recipe.Vegetarian = vegetarian;

                    RecipeList.Add(recipe);
                }

            }
        }



        public static double getSimilarityScore(RecipeQuery input, Recipe examined)
        {
           double cookingMethodScore = CookingMethodUtil.getSimilarityScore(input.CookingMethod, examined.CookingMethod);
           double cookingTimeScore = SimilarityUtil.getSimilarityScore(input.CookingTime, examined.CookingTime, 300);
           double cuisineScore = CuisineUtil.getSimilarityScore(input.Cuisine, examined.Cuisine);
           double halalScore = SimilarityUtil.getSimilarityScore(input.Halal, examined.Halal);
           double healthyScore = SimilarityUtil.getSimilarityScore(input.Healthy, examined.Healthy);  
           double ingredientScore = IngredientUtil.getSimilarityScore(input.Ingredients, examined.Ingredients);
           double mealTypeScore = MealTypeUtil.getSimilarityScore(input.MealType, examined.MealType);
           double nameScore = SimilarityUtil.getSimilarityScore(input.Name, examined.Name);
           double spicyScore = SimilarityUtil.getSimilarityScore(input.Spicy, examined.Spicy);
           double vegetarianScore = SimilarityUtil.getSimilarityScore(input.Vegetarian, examined.Vegetarian);
           
           
            double cookingMethodWeight = getWeight("Cooking Method");
            double cookingTimeWeight = getWeight("Cooking Time");
            double cuisineWeight = getWeight("Cuisine");
            double halalWeight = getWeight("Halal");
            double healthyWeight = getWeight("Healthy");
            double ingredientWeight = getWeight("Ingredient");
            double mealTypeWeight = getWeight("Meal Type");
            double nameWeight = getWeight("Name");
            double spicyWeight = getWeight("Spicy");
            double vegetarianWeight = getWeight("Vegetarian");
            //double avoidedIngredientWeight = getWeight("Avoided Ingredient Penalty");

            double totalWeight = 0;
            if (input.CookingMethod != null) totalWeight += cookingMethodWeight;
            if (input.CookingTime != null) totalWeight += cookingTimeWeight;
            if (input.Cuisine != null) totalWeight += cuisineWeight;
            if (input.Halal != null) totalWeight += halalWeight;
            if (input.Healthy != null) totalWeight += healthyWeight;
            if (input.Ingredients.Count != 0) totalWeight += ingredientWeight;
            if (input.MealType != null) totalWeight += mealTypeWeight;
            if (input.Name != null && !input.Name.Equals("")) totalWeight += nameWeight;
            if (input.Spicy != null) totalWeight += spicyWeight;
            if (input.Vegetarian != null) totalWeight += vegetarianWeight;

            double score = 0;
            if (totalWeight == 0) { // no query
                score = 100;
            }
            else
            {
               score =  cookingMethodScore * cookingMethodWeight +
                    cookingTimeScore * cookingTimeWeight +
                    cuisineScore * cuisineWeight +
                    halalScore * halalWeight +
                    healthyScore * healthyWeight +
                    ingredientScore * ingredientWeight +
                    mealTypeScore * mealTypeWeight +
                    nameScore * nameWeight +
                    spicyScore * spicyWeight +
                    vegetarianScore * vegetarianWeight;
                score = score / totalWeight * 100; // Normalized to 100
            }

            /*
            score = score - avoidedIngredientScore * avoidedIngredientWeight;

            if (score < 0) return 0;
            else return score;
             * */

            // Number of Avoided Ingredients Found
            double avoidedIngredientScore = IngredientUtil.getPenaltyScore(input.AvoidedIngredients, examined.Ingredients);

            if (avoidedIngredientScore > 0) return Math.Round(score * 0.1,2);
            else return Math.Round(score,2);

        }


        public static List<Recipe> getRelevantRecipes(RecipeQuery recipeQuery, int maxCases)
        {

            List<Recipe> recipeListCopy = new List<Recipe>();

            foreach (Recipe recipe in RecipeList)
            {
                double similarityScore = getSimilarityScore(recipeQuery, recipe);
                Recipe r = recipe.clone();
                r.Similarity = similarityScore;
               // if (r.Similarity >= 0)
               // {
                    r.Similarity = similarityScore;
                    recipeListCopy.Add(r);
               // } 
            }

            recipeListCopy.Sort(delegate(Recipe r1, Recipe r2) { return r1.Similarity.CompareTo(r2.Similarity); });
            recipeListCopy.Reverse();
          
            List<Recipe> recipeListCopyCopy = new List<Recipe>();
            int count = 0;
            foreach (Recipe recipe in recipeListCopy)
                {
                   recipeListCopyCopy.Add(recipe);
                   count++;
                   if (count >= maxCases) break;
               }
             return recipeListCopyCopy;
           
        }

        public static bool writeRecipe(Recipe r)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(r.Name);
            sb.AppendLine(r.Cuisine.Name);
            sb.AppendLine(r.MealType.Name);
            sb.AppendLine(r.CookingMethod.Name);

            if (r.Spicy==true) sb.AppendLine("Spicy");
            else sb.AppendLine("NonSpicy");

            if (r.Halal == true) sb.AppendLine("Halal");
            else sb.AppendLine("NonHalal");

            if (r.Healthy == true) sb.AppendLine("Healthy");
            else sb.AppendLine("NonHealthy");

            if (r.Vegetarian == true) sb.AppendLine("Vegetarian");
            else sb.AppendLine("NonVegetarian");

            sb.AppendLine(r.CookingTime.ToString());
            sb.AppendLine(r.ServingPortion.ToString());

            sb.AppendLine();
            sb.AppendLine("Ingredients:");

            foreach (Ingredient ingredient in r.Ingredients)
                sb.AppendLine(ingredient.Name);

            sb.AppendLine();
            sb.AppendLine("Cooking Instructions:");
            sb.AppendLine(r.CookingInstructions);

            String filename = @"CBRData/Recipe/" + r.Name + ".txt";

               if (File.Exists(filename)){
                   MessageBox.Show(r.Name + " recipe exists. Change Recipe Name...");
                   return false;
               } else {
                   System.IO.File.WriteAllText(filename, sb.ToString());
                   RecipeList.Add(r);
                   return true;
               }
            
        }

        public static void setSimilarityWeight()
        {
            if (!File.Exists(WEIGHT_CONFIG_FILE_NAME))
            {
                Console.WriteLine("{0} does not exist.", WEIGHT_CONFIG_FILE_NAME);
                return;
            }

            using (StreamReader sr = File.OpenText(WEIGHT_CONFIG_FILE_NAME))
            {
                String input;
                while ((input = sr.ReadLine()) != null)
                {
                    string[] values = input.Split(':');
                    weightConfigMap.Add(values[0].Trim().ToLower(), Convert.ToInt32(values[1].Trim()));
                }
            }
        }

        public static int getWeight(string key)
        {
            return weightConfigMap[key.ToLower()];
        }

        /*
        public static int getMaximumNumberOfRetrievedCase()
        {
            if (weightConfigMap.ContainsKey("Number of Result Displayed".ToLower()))
                return weightConfigMap["Number of Result Displayed".ToLower()];
            else return 0;
        }
         */
    }
}
